﻿#include "common.h"
#include <stdarg.h>     // 引入可变参数头文件

/*
在 C 语言中，函数的参数列表可以是可变参数，即函数可以接受任意数量的参数。

可变参数的声明语法如下：
    类型名 函数名(int num,...) {
        // 函数体
    }
    其中，... 表示可变参数，函数体内可以通过 va_arg 宏来获取每个参数的值。第一个参数用于计数可变参数格式，在 C 语言中必须有，否则会导致未定义行为

注意：
    1. 可变参数必须在函数声明中最后一个参数，即最后一个参数前面不能有其他参数。
    2. 可变参数只能作为最后一个参数，不能作为中间参数。
    3. 可变参数只能在函数体内使用，不能在函数声明中使用。
    4. 可变参数的类型必须是基本类型，不能是指针、数组、结构体、类等。
    5. 可变参数的实际参数个数由调用者决定，可以是0个、1个或多个。
    6. 可变参数的实际参数类型必须与函数声明中类型一致。
    7. 可变参数的实际参数存储在一个数组中，可以通过 va_arg 宏来获取每个参数的值。
    8. 可变参数的实际参数存储在一个数组中，可以通过 va_start 宏来初始化 va_list 类型的变量，然后通过 va_arg 宏来获取每个参数的值，最后通过 va_end 宏来清理 va_list 类型的变量。


*/


static void print_nums(int num,...) {
    //num 参数是计数参数，必须有
    //va_list是一个用于存储可变参数信息的类型。
    va_list args;

    //va_start宏用于初始化va_list类型的变量 args，使其指向第一个可变参数。va_start的第二个参数是最后一个固定参数，这里是 num。
    va_start(args, num);

    for (int i = 0; i < num; i++) {
        printf("%d ", va_arg(args, int));
    }
    printf("\n");

    //a_end宏用于清理va_list类型的变量args，结束对可变参数的处理。
    va_end(args);
}

static void print_values(int num, ...) {
    va_list args;
    va_start(args, num);

    for (int i = 0; i < num; i++) {
        //va_arg 宏用于从可变参数列表中提取一个参数，并将其转换为指定的类型。每次调用 va_arg 时，ap 会指向下一个参数。
        char type = va_arg(args, char);
        if (type == 'i') {
            int value = va_arg(args, int);
            printf("%d ", value);
        }
        else if (type == 'f') {
            double value = va_arg(args, double); // 注意：float类型会提升为double类型
            printf("%f ", value);
        }
        else if (type == 'c') {
            int value = va_arg(args, int); // char类型会提升为int类型
            printf("%c ", value);
        }
        else if (type == 's') {
            char* value = va_arg(args, char*); // 字符串是以char*传递的
            printf("%s ", value);
        }
        else if (type == 'p') {
            void* value = va_arg(args, void*); // 指针类型会提升为void*类型
            printf("%p ", value);
        }
        else {
            printf("unknown type: %c\n", type);
        }
    }

    va_end(args);
    printf("\n");
}



void test_va_args() {
    // 第一个参数计数，后面是可变参数
    print_nums(4, 10, 20, 30, 40);
    // 如果可变参数个数大于实际传入的参数个数，则会导致未定义行为，可能是内存越界访问等问题
    print_nums(6, 10, 20, 30, 40);

    print_values(4, 'i', 82, 'f', 3.14, 'c', 'x', 's', "hello world");
}